﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoolCode.Entities;
using CoolCode.Data.Linq;
using CoolCode.Linq;
using System.Timers;

namespace CoolCode.Services
{
    public class TipsService : ServiceBase, ITrackService<Tips>, ITipsService,IDisposable
    {
        #region Data Access Object

        private IRepository<Tips> _TipsDao;
        public IRepository<Tips> TipsDao
        {
            get
            {
                if (_TipsDao == null)
                {
                    _TipsDao = this.CreateRepository<Tips>();
                }
                return _TipsDao;
            }
            set
            {
                _TipsDao = value;
            }
        }


        #endregion


        #region ITrackService<Tips> Members

        IRepository<Tips> ITrackService<Tips>.Repository
        {
            get
            {
                return TipsDao;
            }
        }

        public ITrackService Current
        {
            get { return this; }
        }

        #endregion

        private static readonly List<Tips> tipsCache = new List<Tips>();

        private static bool loadTips = false;

        private readonly static object insertMutex = new object();

        private readonly static object loadMutex = new object();

        private static readonly Timer timer = new Timer(120000);
       
        public TipsService()
            : base()
        {
        }

         void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            submitTips();
        }

        private void submitTips()
        {
            lock (insertMutex)
            {
                var tipsForInsert = tipsCache.Where(c => c.ID == 0);
                this.TipsDao.Insert(tipsForInsert);

                var tipsForUpdate = tipsCache.Where(c => c.ID > 0);
                int[] tipsIDs = tipsForUpdate.Select(c => c.ID).ToArray();

                var oldTips = this.TipsDao.List(c => tipsIDs.Contains(c.ID));
                this.TipsDao.Delete(c => tipsIDs.Contains(c.ID));
                this.TipsDao.Insert(tipsForUpdate);
                this.Submit();

                //foreach (var tips in oldTips)
                //{
                //    tips.Text= 
                //}

                //foreach (var tips in tipsCache)
                //{
                //    if (tips.ID == 0)
                //    {
                //        this.TipsDao.Insert(tips);
                //    }
                //    else
                //    {
                //        int[] tipsIDs =
                //    }
                //}
            }
        }

        private void ensureLoadTips()
        {
            if (!loadTips)
            {
                lock (loadMutex)
                {
                    if (!loadTips)
                    {
                        tipsCache.Clear();
                        tipsCache.AddRange(this.TipsDao.List());

                        //timer.Interval = 10000;
                        timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                        timer.Disposed += (sender, e) => submitTips();
                        timer.Enabled = true;
                        loadTips = true;
                    }
                }
            }
        }

        #region ITipsService Members

        public List<Tips> ListTips(string type)
        {
            return ListTips(type, null);
        }

        public List<Tips> ListTips(string type, string prefix)
        {
            ensureLoadTips();
            IEnumerable<Tips> query = null;
            if (string.IsNullOrEmpty(prefix))
                query = tipsCache.Where(c => c.Type == type);
            else
                query = tipsCache.Where(c => c.Type == type && c.Text.Contains(prefix));
            var latestTips = query.OrderByDescending(c => c.UpdateDate).Take(3);
            var popularTips = query.OrderByDescending(c => c.Times).Take(13);
            var list = latestTips.Union(popularTips);
            var result = list.Take(10).ToList();
            return result;
        }

        public string[] ListTipsText(string type, string prefix)
        {
            var list = ListTips(type, prefix);
            return list.Select(c => c.Text).ToArray();
        }

        public void SaveTips(Tips tips)
        {
            if (tips == null) return;
            if (string.IsNullOrEmpty(tips.Text)) return;

            lock (insertMutex)
            {
                var query = tipsCache.Where(c => c.Type == tips.Type && c.Text == tips.Text);
                if (query.Count() > 0)
                {
                    var t = query.First();
                    t.Times++;
                    t.UpdateDate = DateTime.Now;
                }
                else
                {
                    tips.Times = 1;
                    tips.CreateDate = DateTime.Now;
                    tips.UpdateDate = DateTime.Now;
                    tipsCache.Add(tips);
                }
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (timer != null)
                timer.Dispose();
        }

        #endregion
    }
}
